using Google.Protobuf;
using LittleBee.JsonRpc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Asn1.Ocsp;
using Org.BouncyCastle.Security;
using System.ComponentModel;
using System.DirectoryServices.ActiveDirectory;

namespace JrpcTest
{
	public partial class Form1 : Form
	{
		readonly JsonRpcClient _jsonRpcClient = new(65432);
		JsonRpcInterfacesInfo _jsonRpcInterfaceInfo = new JsonRpcInterfacesInfo();
		static readonly string _strJsonRpcLogFileName = "request.log";

		public Form1()
		{
			_jsonRpcClient.OnJsonRpcException += JsonRpcExceptionHandler;
			_jsonRpcClient.Start();

			InitializeComponent();
		}

		private void JsonRpcExceptionHandler(JsonRpcExceptionEventArg args)
		{
			this.Invoke(() => MessageBox.Show(this, $"{args.ErrorType} : {args.Response.ToString(Formatting.None)}", "JsonRpc Error Response"));
		}

		private void Form1_Load(object sender, EventArgs e)
		{
			File.CreateText(_strJsonRpcLogFileName).Close();

			InitJsonRpcInterfacesInfo();
		}

		public void InitJsonRpcInterfacesInfo()
		{
			JObject? joResp = null;

			joResp = _jsonRpcClient!.CallMehod("GetInterfacesInfo", new JObject(), 3000);
			if (joResp == null)
			{
				throw new NullReferenceException($"JsonRpc response return null: GetInterfacesInfo");
			}

			if (joResp!.TryGetValue("result", out JToken? jtResult))
			{
				JObject? joResult = jtResult as JObject;
				if (joResult == null)
					throw new ArgumentException($"JsonRpc response is invalid: {jtResult}");

				_jsonRpcInterfaceInfo.SetJsonRpcInterfacesInfo(joResult);
			}
			else
			{
				throw new InvalidParameterException($"JsonRpc response not include result parameter");
			}

			var joInterfaceInfo = _jsonRpcInterfaceInfo.GetInterfaceList();
			{
				tvInterfaceList.BeginUpdate();

				tvInterfaceList.Nodes.Clear();
				TreeNode tnTop = new TreeNode("JsonRpc Interface List");

				//_jsonRpcInterfaceInfo = new JsonRpcInterfaceInfo();
				_jsonRpcInterfaceInfo.Version = _jsonRpcInterfaceInfo.GetInterfaceVersion();
				Array.ForEach<string>(joInterfaceInfo!.ToArray(), (x) =>
				{
					JsonRpcFunctionInfo funcInfo = new JsonRpcFunctionInfo(x.ToString());
					funcInfo.PropertyChanged += FunctionInfoChanged;
					_jsonRpcInterfaceInfo.InsertFunctionInfo(funcInfo);

					TreeNode tnInterface = new TreeNode(x.ToString());
					tnInterface.Tag = funcInfo;

					JArray jaParams = _jsonRpcInterfaceInfo.GetInterfaceFunctionParams(x.ToString());
					if (jaParams.Count > 1)
					{
						int idx = 1;
						Array.ForEach<JToken>(jaParams.ToArray(), (y) =>
						{
							TreeNode tnParam = tnInterface.Nodes.Add($"[{idx++}]");
							tnParam.Tag = JToken.Parse(y.ToString()).ToString(Formatting.Indented);
						});
					}

					tnTop.Nodes.Add(tnInterface);
				});

				tvInterfaceList.Nodes.Add(tnTop);
				tnTop.Expand();

				tvInterfaceList.EndUpdate();
			}
		}

		public void FunctionInfoChanged(object? sender, PropertyChangedEventArgs e)
		{

		}

		private void twInterfaceList_AfterSelect(object sender, TreeViewEventArgs e)
		{
			tbRequest.Text = String.Empty;
			tbResponse.Text = String.Empty;

			if (sender != tvInterfaceList.Nodes[0])
			{
				if (e.Node != null && e.Node!.Tag != null)
				{
					var funcInfo = e.Node!.Tag as JsonRpcFunctionInfo;
					if (funcInfo != null)
					{
						var reqrspInfo = funcInfo.ReqRspInfo;
						if (reqrspInfo != null)
						{
							if (reqrspInfo.Request != null)
								tbRequest.Text = reqrspInfo.Request.ToString(Formatting.Indented);
							if (reqrspInfo.Response != null)
								tbResponse.Text = reqrspInfo.Response.ToString(Formatting.Indented);
						}
						else
						{
							string param = (e.Node!.Tag as JsonRpcFunctionInfo)!.FuncName;
							// to do:...
							tbRequest.Text = JToken.Parse(_jsonRpcInterfaceInfo.GetInterfaceFunctionParams(param)[0].ToString()).ToString(Formatting.Indented);
						}
					}
					else
					{
						tbRequest.Text = e.Node!.Tag.ToString();
					}
				}
			}
		}

		private void btSend_Click(object sender, EventArgs e)
		{
			if (tvInterfaceList.SelectedNode.Text[0] == '[')
			{
				_jsonRpcClient.CallMethodAsync(tvInterfaceList.SelectedNode.Parent.Text, JObject.Parse(tbRequest.Text))!.ContinueWith((x) =>
				{
					this.Invoke(() => { tbResponse.Text = x.Result.Response!.ToString(); });
				});
			}
			else
			{
				_jsonRpcClient.CallMethodAsync(tvInterfaceList.SelectedNode.Text, JObject.Parse(tbRequest.Text))!.ContinueWith((x) =>
				{
					this.Invoke(() => { tbResponse.Text = x.Result.Response!.ToString(); });
				});
			}
		}
	}
}